local _G = _G
local CurseProfiler = _G.CurseProfiler
local GameObjects = CurseProfiler:NewModule("GameObjects")

local UnitGUID = _G.UnitGUID
local SetMapToCurrentZone = _G.SetMapToCurrentZone
local GetRealZoneText = _G.GetRealZoneText
local GetPlayerMapPosition = _G.GetPlayerMapPosition
local tonumber = _G.tonumber
local pairs = _G.pairs
local math_floor = _G.math.floor

local objectData = {}

local foundNPCObject = false
function GameObjects:OnUpdate(elapsed)
	local guid = UnitGUID("npc")
	local last_foundNPCObject = foundNPCObject
	foundNPCObject = guid and guid:match("^0xF11")
	if foundNPCObject and not last_foundNPCObject then
		local id = tonumber(guid:sub(-12, -7), 16)
		if id <= 1 then
			return
		end
		local objectData_id = objectData[id]
		if not objectData_id then
			objectData_id = {}
			objectData[id] = objectData_id
		end
		SetMapToCurrentZone()
		local zone = GetRealZoneText()
	    local x, y = GetPlayerMapPosition("player")
		objectData_id.zone = zone
		objectData_id.x = x
		objectData_id.y = y
	end
end

local deserialize__text, deserialize__position
local OnDeserialize
function GameObjects:OnSerialize()
	local ZONE = CurseProfiler.getZoneID
	local INT = CurseProfiler.makeSerializedInteger
	local TUPLE = CurseProfiler.makeSerializedTuple
	local savedData = not deserialize__text and {} or OnDeserialize(deserialize__text, deserialize__position, true)
	for id, data in pairs(objectData) do
		savedData[id] = data
	end
	local fullData = {}
	for id, data in pairs(savedData) do
		fullData[TUPLE {
			INT("Int32", id),
			ZONE(data.zone or ''),
			INT("Int16", math_floor((data.x or 0) * 10000 + 0.5)),
			INT("Int16", math_floor((data.y or 0) * 10000 + 0.5)),
		}] = true
	end
	return fullData
end

function OnDeserialize(text, position, run)
	local deserialize = CurseProfiler.deserialize
	
	local data
	if run then
		data = {}
	end
	
	local num
	position, num = deserialize('list', text, position)
	for i = 1, num do
		local id, name, zone, x, y
		position, id = deserialize('Int32', text, position, not run)
		position, zone = deserialize('zone', text, position, not run)
		position, x = deserialize('Int16', text, position, not run)
		position, y = deserialize('Int16', text, position, not run)
		if run then
			data[id] = {
				zone = zone,
				x = x / 10000,
				y = y / 10000,
			}
		end
	end
	
	if run then
		return data
	else
		return position
	end
end

function GameObjects:OnDeserialize(text, position)
	deserialize__text, deserialize__position = text, position
	return OnDeserialize(text, position, false)
end

function GameObjects:ClearCache()
	wipe(objectData)
end
